import random
from flask import request, jsonify, current_app, make_response,session
from info.utils.response_code import RET
from . import passport_blue
from info.utils.captcha.captcha import captcha
from info import redis_store, constants,db
import re
from info.models import User
from info.libs.yuntongxun import sms


'''
1 生成图片验证码(UUID)
浏览器生产UUID ---- 服务器 ----生产验证码图片并关联UUID存储图片内容于redis

'''


@passport_blue.route('/image_code')
def generate_image_code():
    img_code_id = request.args.get('image_code_id')
    if not img_code_id:
        return jsonify(erron=RET.PARAMERR, errmsg='参数错误')

    name, text, image = captcha.generate_captcha()
    try:
        redis_store.setex('Image_code' + img_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR, errmsg='验证码存入redis失败!')
    else:
        response = make_response(image)
        response.headers['Content-Type'] = 'image/jpg'
        print('返回生成的验证码图片成功!')
        return response


'''
2 发送短信验证码(手机号,用户输入的图片验证码,原始UUID)
'''


@passport_blue.route('/sms_code', methods=['POST'])
def send_sms_code():
    mobile = request.json.get('mobile')
    image_code = request.json.get('image_code')
    image_code_id = request.json.get('image_code_id')

    if not all([mobile, image_code, image_code_id]):
        return jsonify(erron=RET.PARAMERR, errmsg='参数不完整！')

    if not re.match(r'1[3456789]\d{9}', mobile):
        return jsonify(erron=RET.PARAMERR, errmsg='手机号不符合规则！')

    try:
        real_image_code = redis_store.get('Image_code' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.PARAMERR, errmsg='获取数据库验证码失败！')

    if not real_image_code:
        return jsonify(erron=RET.PARAMERR, errmsg='验证码已过期！')

    '''
    取到数据,及时从缓存中删除数据
    图片验证码,只能输入一次，错误则刷新，因此是取完数据还没验证就将redis缓存中的删除。
    '''
    try:
        redis_store.delete('Image_code' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)

    if real_image_code.lower() != image_code.lower():
        return jsonify(erron=RET.DATAERR, errmsg='图片验证码不一致')

    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DATAERR, errmsg='用户数据查询失败！')
    else:
        if user is not None:
            return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')

    sms_code = '%06d' % random.randint(0, 999999)
    try:
        redis_store.setex('SMSCode_' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DATAERR, errmsg='短信数据保存失败！')

    # try:
    #     ccp = sms.CCP()
    #     result = ccp.send_template_sms(mobile,[sms_code,constants.SMS_CODE_REDIS_EXPIRES / 60],1)
    # except Exception as e:
    #     current_app.logger.error(e)
    #     return jsonify(errno=RET.THIRDERR,errmsg='发送短信失败')
    print('发送短信前校验通过！')
    result = 0
    print('短信验证码：', sms_code)
    if 0 == result:
        return jsonify(errno=RET.OK, errmsg='发送成功')
    else:
        return jsonify(errno=RET.THIRDERR, errmsg='发送失败')


'''
3 注册(手机号,用户输入的短信验证码,密码)
递进验证,下一步验证上一步的操作,校验数据合法性
'''
@passport_blue.route('/register',methods=['POST'])
def register():

    mobile = request.json.get('mobile')
    sms_code = request.json.get('sms_code')
    password = request.json.get('password')

    if not all([mobile,sms_code,password]):
        return jsonify(erron =RET.PARAMERR,errmsg='数据不完整！')

    if not re.match(r'1[3456789]\d{9}',mobile):
        return jsonify(erron=RET.PARAMERR,errmsg='手机号不合法！')

    '''
    这里--过期redis将删除该键对应的值（None）,因此可以取到该键的值，但是为空
    '''
    try:
        real_sms_code = redis_store.get('SMSCode_'+ mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR,errmsg='获取数据库短信验证码失败！')

    if not real_sms_code:
        return jsonify(errno=RET.NODATA,errmsg='短信验证码过期')

    if sms_code != real_sms_code:
        return jsonify(erron=RET.DATAERR,errmsg='短信验证码不一致！')

    '''
    短信验证码,可以多次输入，因此是取完数据验证通过后再从redis缓存中的删除。
    '''
    try:
        redis_store.delete('SMSCode_'+ mobile)
    except Exception as e:
        current_app.logger.error(e)

    '''
    这里再一次对手机号是否已经注册进行了校验,you have to know why
    '''
    try:
        user  = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DATAERR,errmsg='查询用户信息失败！')
    else:
        if user:
            return jsonify(errno=RET.DATAEXIST,errmsg='手机号已注册')


    '''
    所有校验通关后，进行注册操作---往数据库添加数据---往缓存中添加数据

    构造表的模型类对象，给各个字段赋值。
    密码---不仅仅是赋值：调用了模型类中的方法，对密码进行了sha256加密存储
    '''
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    user.password = password

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR,errmsg='保存数据失败')

    session['user_id'] = user.id
    session['nick_name'] = mobile
    session['mobile'] = user.mobile
    print('注册成功！')
    return jsonify(errno=RET.OK,errmsg='注册成功')

@passport_blue.route('/login',methods=['POST'])
def login():
    mobile = request.json.get('mobile')
    password = request.json.get('password')

    if not all([mobile,password]):
        return jsonify(erron=RET.PARAMERR,errmsg='数据不完整！')

    if not re.match(r'1[3456789]\d{9}',mobile):
        return jsonify(erron=RET.PARAMERR,errmsg='手机号码不合法！')


    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(erron=RET.DBERR,errmsg='查询用户数据失败！')

    # 同时校验密码和用户名,填补安全漏洞
    if user is None or not user.check_password(password):
        return jsonify(errno=RET.DATAERR,errmsg='用户名或密码错误')

    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = mobile

    print('登陆成功！')
    return jsonify(errno=RET.OK, errmsg='登录成功')

"""
用户登录
1、获取参数，mobile、password
2、检查参数的完整性
3、检查手机号格式
4、确认用户已经注册，查询数据库，
5、检查查询结果，确认用户存在
6、验证密码是否正确
7、缓存用户数据到redis数据库中
8、返回结果
:return:
"""

@passport_blue.route('/logout')
def logout():
    session.pop('user_id')
    session.pop('nick_name')
    session.pop('mobile')
    return jsonify(errno=RET.OK,errmsg='OK')